/**
 ******************************************************************************
 * @file           : main.c
 * @brief          : SPI Flash Example
 ******************************************************************************
 * @attention
 *
 * SPI和Flash读写示例
 * 功能：
 *   - SPI初始化
 *   - Flash读取
 *   - Flash写入
 *   - 数据验证
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "stm32h7xx.h"
#include <stdio.h>
#include <string.h>

/* Private defines -----------------------------------------------------------*/
#define FLASH_ADDR      0x000000
#define FLASH_SIZE      256
#define CS_PORT         GPIOA
#define CS_PIN          GPIO_PIN_4

/* Private variables ---------------------------------------------------------*/
SPI_HandleTypeDef hspi1;
uint8_t flash_buffer[FLASH_SIZE];
uint8_t test_data[FLASH_SIZE];

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void spi_init(void);
void usart_init(uint32_t baudrate);
void usart_send_byte(uint8_t byte);
void flash_read(uint32_t addr, uint8_t *data, uint32_t len);
void flash_write(uint32_t addr, uint8_t *data, uint32_t len);
void flash_erase(uint32_t addr);
uint8_t flash_verify(uint32_t addr, uint8_t *data, uint32_t len);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       USART初始化
 *
 * @param[in]   baudrate - 波特率
 *
 * @retval      无
 */
void usart_init(uint32_t baudrate)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    UART_HandleTypeDef huart1 = {0};

    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_USART1_CLK_ENABLE();

    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    huart1.Instance = USART1;
    huart1.Init.BaudRate = baudrate;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
    huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
    huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;

    HAL_UART_Init(&huart1);
}

/**
 * @brief       发送单字节
 *
 * @param[in]   byte - 要发送的字节
 *
 * @retval      无
 */
void usart_send_byte(uint8_t byte)
{
    while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TXE) == RESET);
    USART1->TDR = byte;
}

/**
 * @brief       printf重定向
 *
 * @param[in]   ch - 字符
 * @param[in]   f - 文件指针
 *
 * @retval      int - 字符
 */
int fputc(int ch, FILE *f)
{
    usart_send_byte((uint8_t)ch);
    return ch;
}

/**
 * @brief       SPI初始化
 *
 * @param       无
 *
 * @retval      无
 */
void spi_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_SPI1_CLK_ENABLE();

    /* 配置SPI引脚 */
    GPIO_InitStruct.Pin = GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* 配置SPI */
    hspi1.Instance = SPI1;
    hspi1.Init.Mode = SPI_MODE_MASTER;
    hspi1.Init.Direction = SPI_DIRECTION_2LINES;
    hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
    hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
    hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
    hspi1.Init.NSS = SPI_NSS_SOFT;
    hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
    hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
    hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
    hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    hspi1.Init.CRCPolynomial = 0x0;
    hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
    hspi1.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
    hspi1.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
    hspi1.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
    hspi1.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
    hspi1.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
    hspi1.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
    hspi1.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
    hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
    hspi1.Init.IOSwap = SPI_IO_SWAP_DISABLE;

    HAL_SPI_Init(&hspi1);
}

/**
 * @brief       Flash读取
 *
 * @param[in]   addr - 地址
 * @param[out]  data - 数据缓冲区
 * @param[in]   len - 长度
 *
 * @retval      无
 */
void flash_read(uint32_t addr, uint8_t *data, uint32_t len)
{
    uint8_t cmd[4] = {0x03, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF};

    HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi1, cmd, 4, 1000);
    HAL_SPI_Receive(&hspi1, data, len, 1000);
    HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);
}

/**
 * @brief       Flash写入
 *
 * @param[in]   addr - 地址
 * @param[in]   data - 数据缓冲区
 * @param[in]   len - 长度
 *
 * @retval      无
 */
void flash_write(uint32_t addr, uint8_t *data, uint32_t len)
{
    uint8_t cmd = 0x06;

    /* 写使能 */
    HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi1, &cmd, 1, 1000);
    HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);

    HAL_Delay(1);

    /* 写数据 */
    uint8_t write_cmd[4] = {0x02, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF};
    HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi1, write_cmd, 4, 1000);
    HAL_SPI_Transmit(&hspi1, data, len, 1000);
    HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);

    HAL_Delay(10);
}

/**
 * @brief       Flash擦除
 *
 * @param[in]   addr - 地址
 *
 * @retval      无
 */
void flash_erase(uint32_t addr)
{
    uint8_t cmd = 0x06;

    /* 写使能 */
    HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi1, &cmd, 1, 1000);
    HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);

    HAL_Delay(1);

    /* 擦除 */
    uint8_t erase_cmd[4] = {0x20, (addr >> 16) & 0xFF, (addr >> 8) & 0xFF, addr & 0xFF};
    HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_RESET);
    HAL_SPI_Transmit(&hspi1, erase_cmd, 4, 1000);
    HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET);

    HAL_Delay(100);
}

/**
 * @brief       Flash验证
 *
 * @param[in]   addr - 地址
 * @param[in]   data - 数据缓冲区
 * @param[in]   len - 长度
 *
 * @retval      uint8_t - 1=成功, 0=失败
 */
uint8_t flash_verify(uint32_t addr, uint8_t *data, uint32_t len)
{
    uint8_t read_data[FLASH_SIZE];

    flash_read(addr, read_data, len);

    for(uint32_t i = 0; i < len; i++)
    {
        if(read_data[i] != data[i])
        {
            return 0;
        }
    }

    return 1;
}

/**
 * @brief       系统时钟配置
 *
 * @param       无
 *
 * @retval      无
 */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLM = 5;
    RCC_OscInitStruct.PLL.PLLN = 160;
    RCC_OscInitStruct.PLL.PLLP = 2;
    RCC_OscInitStruct.PLL.PLLQ = 4;
    RCC_OscInitStruct.PLL.PLLR = 2;
    RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL_RANGE_VCO_250_500M;
    RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL_VCORANGE_WIDE;
    RCC_OscInitStruct.PLL.PLLFRACN = 0;
    HAL_RCC_OscConfig(&RCC_OscInitStruct);

    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
                                  | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4);
}

/**
 * @brief       主函数
 *
 * @param       无
 *
 * @retval      int
 */
int main(void)
{
    /* 初始化 */
    HAL_Init();
    SystemClock_Config();
    usart_init(115200);
    spi_init();

    /* 打印欢迎信息 */
    printf("\r\n");
    printf("================================\r\n");
    printf("STM32H7xx SPI Flash Example\r\n");
    printf("================================\r\n");
    printf("Flash Address: 0x%06X\r\n", FLASH_ADDR);
    printf("Flash Size: %d bytes\r\n", FLASH_SIZE);
    printf("\r\n");

    /* 初始化测试数据 */
    for(int i = 0; i < FLASH_SIZE; i++)
    {
        test_data[i] = i & 0xFF;
    }

    /* 擦除Flash */
    printf("Erasing Flash...\r\n");
    flash_erase(FLASH_ADDR);
    printf("Flash erased!\r\n\r\n");

    /* 写入Flash */
    printf("Writing Flash...\r\n");
    flash_write(FLASH_ADDR, test_data, FLASH_SIZE);
    printf("Flash written!\r\n\r\n");

    /* 读取Flash */
    printf("Reading Flash...\r\n");
    flash_read(FLASH_ADDR, flash_buffer, FLASH_SIZE);
    printf("Flash read!\r\n\r\n");

    /* 验证数据 */
    printf("Verifying data...\r\n");
    if(flash_verify(FLASH_ADDR, test_data, FLASH_SIZE))
    {
        printf("Data verification: PASSED!\r\n");
    }
    else
    {
        printf("Data verification: FAILED!\r\n");
    }

    printf("\r\n");

    /* 主循环 */
    while(1)
    {
        printf("Flash test completed!\r\n");
        HAL_Delay(2000);
    }

    return 0;
}

/**
 * @brief       系统异常处理
 *
 * @param       无
 *
 * @retval      无
 */
void HardFault_Handler(void)
{
    while(1)
    {
        HAL_Delay(100);
    }
}
